#include "amever.h"

int parseQueue(struct chain_set *qset) {
	if (!qset->len)
		return 0;
	struct chain_node *qnode = 0;
	while (qset->len && qset->first && qset->first->index < s.clock && !s.status.shutting) {
		if (qset->first->val) {
			struct sexec *sex =  (struct sexec *)qset->first->val;
			if (sex->proc)
				sex->proc(sex);
		}
		qShut(qset->first->val);
//		chain_shift(qset, qnode)
		chain_nodeShut(qset->first);
		if (qset->len == 0)
			amelog("Q's empty now.\n");
	}
	return 0;
}

int qAdd(struct chain_set *q, unsigned int index, int (*proc)(struct sexec *), void *val) {
	struct sexec *me = malloc(sizeof(struct sexec)); // freed in qShut
	me->proc = proc;
	me->val = val;
	chain_nodeInit(q, me, index, 0);
	return 0;
}

inline static void qShut (struct sexec *sex) {
	if (sex != 0) {
		if (sex->val != 0) {
			free(sex->val);
		}
		free(sex);
	}
	return;
}

int qCloseFd(struct sexec *sex) {
	int fd = GAMEW(sex, 0);
	/*
	if (close(fd)) {
		amelog("Error closing fd [%d].\n", fd);
	}
	*/
	return;
}

int qSendToChar(struct sexec *sex) {
	if (!sex || !sex->val || GAMEW(sex, 0) > s.highest_fd) {
		amelog("warning: empty chunk in chain...\n");
		return;
	}
	int fd = GAMEW(sex, 0);

	if (s.fds[fd].type != FD_CLIENT)
		return;

	struct client *c = CLIENT(fd);

	if (c == 0)
		return;

	int code = GAMEW(sex, 2);
	int size   = GAMEB(sex, 4);
	char tmp[128];
	strcpy(tmp, GAMEP(sex, 5));

	if (WFIFOPR(c, size + 3) <= 0)
		return 1;
	WFIFOW(c, 0) = GAMEW(sex, 2);
	WFIFOB(c, 2) = 3 + sprintf(WFIFOP(c, 3), "%s", GAMEP(sex, 5));
	WFIFOSP(c, WFIFOB(c, 2));
	amelog("Message \"%s\" sent.\n", WFIFOP(c, 3));
	return;
}

int qAddMsg(struct client *to,  const char *msg, int in) {
	if (!to || !msg)  {
		amelog("Wrong message\n");
		return;
	}
	struct sexec *sex = (struct sexec *)malloc(sizeof(struct sexec)); // freed in qShut
	sex->val = (char *)malloc(strlen(msg) + 10); // also freed int qShut
	sex->proc = qSendToChar;

	GAMEW(sex, 0) = to->fd;
	GAMEW(sex, 2) = 0x00; // System
	GAMEB(sex, 4) = 3 + sprintf(GAMEP(sex, 5), "%s", msg);

	if (!chain_nodeInit(s.ameQ, sex, s.clock+in, 0)) {
		qShut(sex);
	}
	return;
}

int qAddPack(struct client *to, const char *packet, int size, int in) {
	struct sexec *sex = (struct sexec *)malloc(sizeof(struct sexec)); // freed in qShut
	sex->val = malloc(size + 2);
	GAMEW(sex, 0) = to->fd;
	GAMEW(sex, 2) = size;
	memcpy(GAMEP(sex, 4), packet, size);
	sex->proc = qSendPack;
	chain_nodeInit(s.ameQ, sex, s.clock+in, 0);
	return;
}

int qSendPack(struct sexec *sex) {
	if (s.fds[GAMEW(sex, 0)].type != FD_CLIENT)
		return 1;
	struct client *me = CLIENT(GAMEW(sex, 0));
	memcpy(WFIFOP(me, 0), GAMEP(sex, 4), GAMEW(sex, 2));
	WFIFOSP(me, GAMEW(sex, 2));
	return 0;
}

int q_charParseMov(struct sexec *sex) {
	amelog("in parseMov\n");
	struct world_char *c = (struct world_char *)GAMEL(sex, 0);
	if (c == 0 || c->steps == 0 || c->steps->first == 0) {
		amelog("Invalid char...\n");
		return 0;
	}

	int x = GAMEW(sex, 4);
	int y = GAMEW(sex, 6);
	int x0 = c->cell->X;
	int y0 = c->cell->Y;
	int xn = CELL(c->steps->first->val)->X;
	int yn = CELL(c->steps->first->val)->Y;
	int x1 = (x0 + (xn-x0)) < 0 ? 0 : (x0 + (xn-x0));
	int y1 = (y0 + (yn-y0)) < 0 ? 0 : (y0 + (yn-y0));
	
	amelog("Parsing char from %d:%d to %d:%d.\n", c->cell->X, c->cell->Y, x, y);
	amelog("x0 %d y0 %d : x1 %d y1 %d\n", x0, y0, x1, y1);
	
	if (x1 < 0 || x1 > MAP_MAX_WIDTH || y1 < 0 || y1 > MAP_MAX_WIDTH ||
		(!c->cell->wmap->cells[y1][x1]) || (c->cell->wmap->cells[y1][x1]->passable == 0)
	) {
		amelog("Error ror.\n");
		chain_setClear(c->steps);
		char_stop(c);
		return 0;
	}
	
	chain_nodeShut(c->steps->first);
	


	amelog("Past...\n");

	struct chain_set *tmp = chain_setInit(0,0,255);
	if (map_foreach(WO_CHAR, c->cell, CHAR_RADIUS, tmp)) {
		struct chain_node *node;
		for (node=tmp->first;node;node=node->next) {
			if (node->val != c->client && CHAR(node->val) && CHAR(node->val)->client) {
				WFIFOPR(CHAR(node->val)->client, 8);
				WFIFOW(CHAR(node->val)->client, 0) = 20;
				WFIFOW(CHAR(node->val)->client, 2) = c->id;
				WFIFOW(CHAR(node->val)->client, 4) = x;
				WFIFOW(CHAR(node->val)->client, 6) = y;
				WFIFOSP(CHAR(node->val)->client, 8);
/*
				if (c->steps->first) {
					WFIFOPR(CHAR(node->val)->client, 8);
					WFIFOW(CHAR(node->val)->client, 0) = 21;
					WFIFOW(CHAR(node->val)->client, 2) = c->id;
					WFIFOW(CHAR(node->val)->client, 4) = CELL(c->steps->first->val)->X;
					WFIFOW(CHAR(node->val)->client, 6) = CELL(c->steps->first->val)->Y;
					WFIFOSP(CHAR(node->val)->client, 8);
				}
*/
			}
		}
	}
	chain_setShut(tmp);
	return 0;
}

int q_charAddMov(struct world_char *c, int x, int y) {
	struct sexec *sex = (struct sexec *)malloc(sizeof(struct sexec));
	sex->proc = q_charParseMov;
	sex->val = malloc(8);
	GAMEL(sex, 0) = (unsigned int)c;
	GAMEW(sex, 4) = x;
	GAMEW(sex, 6) = y;
	chain_nodeInit(s.ameQ, sex, s.clock+((255/c->props.speed)*1000 * (c->steps->len+1)), 0);
	return 0;
}
